

package com.urick.spi;

import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class ServiceLoader {
    /**
     * 缓存已加载SPI拓展接口服务实例信息
     */
    private static final Map<Class<?>, Collection<Class<?>>> CACEH_SERVICES = new ConcurrentHashMap<>();

    /**
     * 加载SPI接口拓展实现类
     *
     * @param service 服务接口
     * @return 实现实例
     */
    public static <T> Collection<T> load(final Class<T> service) {
        if (CACEH_SERVICES.containsKey(service)) {
            return newServiceInstancesFromCache(service);
        }
        Collection<T> result = new LinkedHashSet<T>();
        for (T each : java.util.ServiceLoader.load(service)) {
            result.add(each);
            cacheServiceClass(service, each);
        }
        return result;
    }

    /**
     * 缓存加载接口实例
     *
     * @param service  SPI接口Class
     * @param instance 实例
     */
    private static <T> void cacheServiceClass(final Class<T> service, final T instance) {
        if (!CACEH_SERVICES.containsKey(service)) {
            CACEH_SERVICES.put(service, new LinkedHashSet<>());
        }
        CACEH_SERVICES.get(service).add(instance.getClass());
    }

    /**
     * 从缓存中获取实例类型定义，并创建实例
     *
     * @param service
     * @return 实例
     */
    private static <T> Collection<T> newServiceInstancesFromCache(Class<T> service) {
        Collection<T> result = new LinkedHashSet<T>();
        for (Class<?> each : CACEH_SERVICES.get(service)) {
            result.add((T) newServiceInstance(each));
        }
        return result;
    }

    private static Object newServiceInstance(final Class<?> clazz) {
        try {
            return clazz.newInstance();
        } catch (IllegalAccessException | InstantiationException e) {
            throw new RuntimeException(e);
        }
    }
}
